package com.engine4cloud.tdf.supervision.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.engine4cloud.tdf.admin.api.entity.SysDept;
import com.engine4cloud.tdf.admin.api.feign.RemoteDeptService;
import com.engine4cloud.tdf.common.core.constant.SecurityConstants;
import com.engine4cloud.tdf.common.core.constant.SupervisionBusinessConstants;
import com.engine4cloud.tdf.common.core.constant.enums.CorElectronicFenceRuleTypeEnum;
import com.engine4cloud.tdf.common.core.constant.enums.ElectronicFenceTypeEnum;
import com.engine4cloud.tdf.common.core.exception.ValidateCodeException;
import com.engine4cloud.tdf.common.core.util.R;
import com.engine4cloud.tdf.common.core.util.RetOps;
import com.engine4cloud.tdf.common.data.web.query.Pages;
import com.engine4cloud.tdf.common.data.web.query.Queries;
import com.engine4cloud.tdf.common.data.web.response.PageInfo;
import com.engine4cloud.tdf.common.data.web.response.Params;
import com.engine4cloud.tdf.common.security.service.TdfUser;
import com.engine4cloud.tdf.common.security.util.SecurityUtils;
import com.engine4cloud.tdf.supervision.convert.JzdxElectronicFenceConvert;
import com.engine4cloud.tdf.supervision.dto.result.*;
import com.engine4cloud.tdf.supervision.dto.JzdxElectronicFenceDTO;
import com.engine4cloud.tdf.supervision.dto.create.JzdxElectronicFenceCreateDTO;
import com.engine4cloud.tdf.supervision.dto.query.JzdxCustomFenceQueryDTO;
import com.engine4cloud.tdf.supervision.dto.query.JzdxElectronicFenceQueryDTO;
import com.engine4cloud.tdf.supervision.dto.result.*;
import com.engine4cloud.tdf.supervision.dto.update.JzdxElectronicFenceUpdateDTO;
import com.engine4cloud.tdf.supervision.entity.JzdxElectronicFenceEntity;
import com.engine4cloud.tdf.supervision.mapper.JzdxElectronicFenceMapper;
import com.engine4cloud.tdf.supervision.service.AreaFenceService;
import com.engine4cloud.tdf.supervision.service.JzdxCustomFenceService;
import com.engine4cloud.tdf.supervision.service.JzdxElectronicFenceService;
import com.engine4cloud.tdf.supervision.service.JzdxService;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 矫正对象电子围栏
 *
 * @author wenjie
 * @date 2024-04-22 16:05:12
 */
@Service
public class JzdxElectronicFenceServiceImpl extends ServiceImpl<JzdxElectronicFenceMapper, JzdxElectronicFenceEntity> implements JzdxElectronicFenceService {
    @Resource
    private JzdxService jzdxService;

    @Resource
    private JzdxCustomFenceService jzdxCustomFenceService;

    @Resource
    private AreaFenceService areaFenceService;

    @Resource
    private RemoteDeptService remoteDeptService;

    @Override
    public PageInfo<JzdxElectronicFenceResultDTO> pageList(Params pageable, JzdxElectronicFenceQueryDTO dto) {
        Page<JzdxElectronicFenceEntity> page = page(Pages.page(pageable), wrapper(dto));
        return Pages.convert(page, JzdxElectronicFenceConvert.INSTANCE::convert);
    }

    @Override
    public PageInfo<JzdxCustomFenceSelectResultDTO> customPageList(Params pageable, ElectronicFenceTypeEnum fenceType, String keywords) {
        R<List<Long>> deptIdRemoteList = remoteDeptService.getDescendantIdList(SecurityUtils.getUser().getDeptId(), SecurityConstants.FROM_IN);

        List<Long> deptIdList = RetOps.of(deptIdRemoteList).getData().filter(CollectionUtils::isNotEmpty)
                .orElseThrow(() -> new ValidateCodeException("没有数据权限!"));

        IPage<JzdxCustomFenceSelectResultDTO> page = this.baseMapper.pageList(Pages.page(pageable), fenceType.getType(), keywords, deptIdList);
        page.setRecords(this.setFenceList(page.getRecords()));
        return Pages.convert(page);
    }

    @Override
    public JzdxElectronicFenceResultDTO getById(Long id) {
        JzdxElectronicFenceResultDTO result = JzdxElectronicFenceConvert.INSTANCE.convert(super.getById(id));
        //设置行政区划围栏列表
        this.setAreaFenceList(result);
        //设置围栏坐标
        this.setCoordinateList(result);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean create(JzdxElectronicFenceCreateDTO dto) {
        JzdxResultDTO dx = Optional.ofNullable(jzdxService.getByCode(dto.getRybh()))
                .orElseThrow(() -> new ValidateCodeException("矫正对象数据不存在"));

        TdfUser user = SecurityUtils.getUser();
        if (Objects.equals(ElectronicFenceTypeEnum.AREA, dto.getWllx())) {
            String fenceName = this.getAreaFenceName(dto.getAreaFenList());
            return super.save(JzdxElectronicFenceConvert.INSTANCE.create(dto, fenceName, user.getTenantId()));
        } else {
            if (CollectionUtils.isEmpty(dto.getCoordinateList())) {
                throw new ValidateCodeException("自定义围栏坐标集不能为空");
            }

            JzdxElectronicFenceEntity entity = JzdxElectronicFenceConvert.INSTANCE.create(dto, dx.getXm() + "-" + dx.getGrlxdh(), user.getTenantId());
            jzdxCustomFenceService.updateBatch(dto.getRybh(), entity.getLcbh(), dto.getCoordinateList());
            return super.save(entity);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(JzdxElectronicFenceUpdateDTO dto) {

        JzdxElectronicFenceEntity fenceEntity = Optional.ofNullable(super.getById(dto.getId()))
                .orElseThrow(() -> new ValidateCodeException("围栏数据不存在"));

        JzdxResultDTO dx = Optional.ofNullable(jzdxService.getByCode(fenceEntity.getRybh()))
                .orElseThrow(() -> new ValidateCodeException("矫正对象数据不存在"));

        if (Objects.equals(ElectronicFenceTypeEnum.AREA, fenceEntity.getWllx())) {
            String fenceName = this.getAreaFenceName(dto.getAreaFenList());
            return super.updateById(JzdxElectronicFenceConvert.INSTANCE.update(dto, fenceEntity.getWllx(), fenceName));
        } else {
            if (CollectionUtils.isEmpty(dto.getCoordinateList())) {
                throw new ValidateCodeException("自定义围栏坐标集不能为空");
            }

            jzdxCustomFenceService.updateBatch(fenceEntity.getRybh(), fenceEntity.getLcbh(), dto.getCoordinateList());
            return super.updateById(JzdxElectronicFenceConvert.INSTANCE.update(dto, fenceEntity.getWllx(), dx.getXm() + "-" + dx.getGrlxdh()));
        }
    }

    @Override
    public List<JzdxElectronicFenceResultDTO> findList(JzdxElectronicFenceQueryDTO query) {
        return super.list(wrapper(query)).stream().map(JzdxElectronicFenceConvert.INSTANCE::convert).toList();
    }

    @Override
    public Boolean createDefault(String code) {
        JzdxResultDTO dx = Optional.ofNullable(jzdxService.getByCode(code))
                .orElseThrow(() -> new ValidateCodeException("矫正对象数据不存在"));

        TdfUser user = SecurityUtils.getUser();

        //已有默认的电子围栏不再添加（常见于执行地变更转入）
        List<JzdxElectronicFenceResultDTO> fenceList = this.findList(new JzdxElectronicFenceQueryDTO(dx.getRybh(), ElectronicFenceTypeEnum.AREA, CorElectronicFenceRuleTypeEnum.RESTRICTED_DEPARTURE));
        if (CollectionUtils.isNotEmpty(fenceList)) {
            return true;
        }

        //设置电子围栏
        JzdxElectronicFenceDTO fence = this.getDefaultFence(dx.getGdjzdszs(), dx.getGdjzdszds(), dx.getGdjzdszxq());
        if (Objects.nonNull(fence)) {
            JzdxElectronicFenceEntity entity = JzdxElectronicFenceConvert.INSTANCE.createDefault(dx, fence, user.getTenantId());
            return super.save(entity);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeBatchByCode(String code) {
        List<JzdxElectronicCoordinateResultDTO> electronicList = findCoordinateList(code);
        if (CollectionUtils.isNotEmpty(electronicList)) {
            super.removeBatchByIds(electronicList.stream().map(JzdxElectronicCoordinateResultDTO::getId).toList());
        }
    }

    @Override
    public List<JzdxElectronicCoordinateResultDTO> findCoordinateList(String code) {
        return this.baseMapper.findCoordinateList(code);
    }

    @Override
    public AreaFenceResultDTO findAreaFence(Long deptId) {
        R<SysDept> remoteDept = remoteDeptService.detail(deptId, SecurityConstants.FROM_IN);

        SysDept dept = RetOps.of(remoteDept).getData()
                .orElseThrow(() -> new ValidateCodeException("没有数据权限!"));

        if (StringUtils.isEmpty(dept.getOrgCode()) || dept.getOrgCode().length() < SupervisionBusinessConstants.ORG_CODE_SPLIT_END_INDEX) {
            throw new ValidateCodeException("所属部门数据错误!");
        }

        String fenceCode = dept.getOrgCode().substring(SupervisionBusinessConstants.ORG_CODE_SPLIT_START_INDEX,
                SupervisionBusinessConstants.ORG_CODE_SPLIT_END_INDEX);
        return areaFenceService.getByCode(fenceCode);
    }

    private JzdxElectronicFenceDTO getDefaultFence(String provinceCode, String cityCode, String countyCode) {
        JzdxElectronicFenceDTO fence = new JzdxElectronicFenceDTO();
        if (StringUtils.isEmpty(provinceCode) || StringUtils.isEmpty(cityCode) || StringUtils.isEmpty(countyCode)) {
            return null;
        }

        AreaFenceResultDTO provinceFence = areaFenceService.getByCode(provinceCode);
        AreaFenceResultDTO cityFence = areaFenceService.getByCode(cityCode);
        AreaFenceResultDTO countyFence = areaFenceService.getByCode(countyCode);

        if (Objects.nonNull(provinceFence)) {
            fence.setCode(provinceCode);
            fence.setName(provinceFence.getName());
            if (Objects.nonNull(cityFence)) {
                fence.setCode(cityCode);
                fence.setName(provinceFence.getName() + "/" + cityFence.getName());
                if (Objects.nonNull(countyFence)) {
                    fence.setCode(countyCode);
                    fence.setName(provinceFence.getName() + "/" + cityFence.getName() + "/" + countyFence.getName());
                    return fence;
                }
            } else {
                if (Objects.nonNull(countyFence)) {
                    fence.setCode(countyCode);
                    fence.setName(provinceFence.getName() + "/" + countyFence.getName());
                }
            }
        } else {
            return null;
        }

        return fence;
    }

    private String getAreaFenceName(List<String> fenceList) {
        if (CollectionUtils.isEmpty(fenceList)) {
            throw new ValidateCodeException("行政区划围栏父子集不能为空");
        }

        String fenceName;

        AreaFenceResultDTO provinceFence = Optional.ofNullable(areaFenceService.getByCode(fenceList.get(SupervisionBusinessConstants.AREA_PROVINCE_INDEX)))
                .orElseThrow(() -> new ValidateCodeException("电子围栏-省-数据不存在"));

        fenceName = provinceFence.getName();

        if (fenceList.size() >= SupervisionBusinessConstants.AREA_COUNTY_CITY_LENGTH) {
            AreaFenceResultDTO cityFence = areaFenceService.getByCode(fenceList.get(SupervisionBusinessConstants.AREA_CITY_INDEX));

            if (Objects.nonNull(cityFence)) {
                fenceName = fenceName + "/" + cityFence.getName();
            }

            if (fenceList.size() >= SupervisionBusinessConstants.AREA_COUNTY_ARRAY_LENGTH) {
                AreaFenceResultDTO countyFence = areaFenceService.getByCode(fenceList.get(SupervisionBusinessConstants.AREA_COUNTY_INDEX));

                if (Objects.nonNull(countyFence)) {
                    fenceName = fenceName + "/" + countyFence.getName();
                }
            }
        }

        return fenceName;
    }

    private void setAreaFenceList(JzdxElectronicFenceResultDTO dto) {
        if (Objects.nonNull(dto) && Objects.equals(ElectronicFenceTypeEnum.AREA.getType(), dto.getWllx())) {
            List<String> areaFenceList = new ArrayList<>();
            dto.setAreaFenList(areaFenceList);

            AreaFenceResultDTO countyFence = areaFenceService.getByCode(dto.getWlbh());
            if (Objects.isNull(countyFence)) {
                return;
            }

            AreaFenceResultDTO cityFence = areaFenceService.getByCode(countyFence.getPcode());
            if (Objects.isNull(cityFence)) {
                areaFenceList.add(countyFence.getCode());
                return;
            }

            AreaFenceResultDTO provinceFence = areaFenceService.getByCode(cityFence.getPcode());
            if (Objects.isNull(provinceFence) || Objects.equals(SupervisionBusinessConstants.AREA_FENCE_ROOT_CODE, provinceFence.getPcode())) {
                areaFenceList.add(cityFence.getCode());
                areaFenceList.add(countyFence.getCode());
                return;
            }

            areaFenceList.add(provinceFence.getCode());
            areaFenceList.add(cityFence.getCode());
            areaFenceList.add(countyFence.getCode());
        }
    }

    private void setCoordinateList(JzdxElectronicFenceResultDTO dto) {
        if (Objects.equals(ElectronicFenceTypeEnum.AREA.getType(), dto.getWllx())) {
            AreaFenceResultDTO areaFence = areaFenceService.getByCode(dto.getWlbh());
            if (Objects.nonNull(areaFence)) {
                List<String> coordinateList = new ArrayList<>();
                coordinateList.add(areaFence.getCoordinate());
                dto.setCoordinateList(coordinateList);
            }
        } else {
            List<JzdxCustomFenceResultDTO> customFenceList = jzdxCustomFenceService.find(new JzdxCustomFenceQueryDTO(dto.getRybh(), dto.getLcbh()));
            if (CollectionUtils.isNotEmpty(customFenceList)) {
                dto.setCoordinateList(customFenceList.stream().map(JzdxCustomFenceResultDTO::getCoordinate).toList());
            }
        }
    }

    private List<JzdxCustomFenceSelectResultDTO> setFenceList(List<JzdxCustomFenceSelectResultDTO> recordList) {
        if (CollectionUtils.isEmpty(recordList)) {
            return recordList;
        }

        recordList.forEach(record -> {
            List<JzdxCustomFenceResultDTO> customFenceList = jzdxCustomFenceService.find(new JzdxCustomFenceQueryDTO(record.getRybh(), record.getLcbh()));
            if (CollectionUtils.isNotEmpty(customFenceList)) {
                record.setCoordinateList(customFenceList.stream().map(JzdxCustomFenceResultDTO::getCoordinate).toList());
            }
        });

        return recordList;
    }

    private LambdaQueryWrapper<JzdxElectronicFenceEntity> wrapper(JzdxElectronicFenceQueryDTO query) {
        LambdaQueryWrapper<JzdxElectronicFenceEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(JzdxElectronicFenceEntity::getId, v));
        Queries.accept(query.getRybh(), v -> wrapper.eq(JzdxElectronicFenceEntity::getRybh, v));
        Queries.accept(query.getWllx(), v -> wrapper.eq(JzdxElectronicFenceEntity::getWllx, v));
        Queries.accept(query.getXzgz(), v -> wrapper.eq(JzdxElectronicFenceEntity::getXzgz, v));
        Queries.accept(query.getXzgz(), v -> wrapper.eq(JzdxElectronicFenceEntity::getXzgz, v));
        return wrapper;
    }
}